package repository

import (
	"github.com/lab-online/internal/course/constant"
	"github.com/lab-online/internal/course/entity"
	"github.com/lab-online/internal/course/infra/model"
	"github.com/lab-online/pkg/database"
	"github.com/lab-online/pkg/util"
)

func (r *Repository) GetCourseByID(id uint) (entity.CourseEntity, error) {
	if id <= 0 {
		return nil, constant.DBErrCourseNotFound
	}

	course := &model.Course{}
	if err := r.db.First(course, id).Error; err != nil {
		return nil, errorHandler(err)
	}

	return course.ToEntity(nil), nil
}

// GetCourseWithExperiments 获取课程及其实验列表
func (r *Repository) GetCourseWithExperiments(id uint) (entity.CourseEntity, error) {
	course := &model.Course{}
	courseExperiments := []model.CourseExperiment{}

	if err := r.db.Preload("Experiments").First(course, id).Error; err != nil {
		return nil, errorHandler(err)
	}
	if err := r.db.Find(&courseExperiments, "course_id = ?", id).Error; err != nil {
		return nil, constant.DBErrUnknown
	}

	return course.ToEntity(courseExperiments), nil
}

func (r *Repository) GetCourses(courseEntity entity.CourseEntity) ([]entity.CourseEntity, error) {
	query := model.NewCourse(model.WithCourseID(courseEntity.GetID()))
	var courses []*model.Course
	if err := r.db.
		Where(query).
		Where("name LIKE ?", "%"+courseEntity.GetName()+"%").
		Find(&courses).Error; err != nil {
		return nil, errorHandler(err)
	}

	return util.SliceMap(courses, func(course *model.Course) entity.CourseEntity {
		return course.ToEntity(nil)
	}), nil
}

func (r *Repository) GetExperimentByID(id uint) (entity.ExperimentEntity, error) {
	experiment := &model.Experiment{}
	if err := r.db.First(experiment, id).Error; err != nil {
		return nil, errorHandler(err)
	}

	return experiment.ToEntity(), nil
}

func (r *Repository) SearchExperiments(
	experimentEntity entity.ExperimentEntity,
) ([]entity.ExperimentEntity, error) {
	var (
		query       = model.NewExperiment(model.WithExperimentID(experimentEntity.GetID()))
		experiments []*model.Experiment
		dbErr       error
	)

	if experimentEntity.GetID() != 0 {
		dbErr = r.db.
			Where("id = ?", experimentEntity.GetID()).
			Limit(1).Find(&experiments).Error
	} else {
		dbErr = r.db.
			Where(query).
			Where("name LIKE ?", "%"+experimentEntity.GetName()+"%").
			Find(&experiments).Error
	}
	if dbErr != nil {
		return nil, constant.DBErrUnknown
	}

	return util.SliceMap(experiments, func(experiment *model.Experiment) entity.ExperimentEntity {
		return experiment.ToEntity()
	}), nil
}

func (r *Repository) CheckCourseExperimentExists(courseID, experimentID uint) (bool, error) {
	if err := r.db.Take(&model.CourseExperiment{
		CourseID:     courseID,
		ExperimentID: experimentID,
	}).Error; err != nil {
		if database.IsRecordNotFound(err) {
			return false, nil
		}
		return false, constant.DBErrUnknown
	}
	return true, nil
}
